home *** CD-ROM | disk | FTP | other *** search
/ Resource Library: Multimedia / Resource Library: Multimedia.iso / sgml / msdos / sgml07 / main.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-03-27  |  11.2 KB  |  535 lines

  1. /* main.c -
  2.    Main program for sgmls.
  3.  
  4.      Written by James Clark (jjc@jclark.com).
  5. */
  6.  
  7. #include "config.h"
  8. #include "std.h"
  9. #include "getopt.h"
  10. #include "entity.h"           /* Templates for entity control blocks. */
  11. #include "adl.h"              /* Definitions for attribute list processing. */
  12. #include "sgmlmain.h"         /* Main interface to SGML services. */
  13. #include "appl.h"
  14.  
  15. #define READCNT 512
  16.  
  17. /* Before using argv[0] in error messages, strip off everything up to and
  18. including the last character in prog that occurs in PROG_PREFIX. */
  19.  
  20. #ifndef PROG_PREFIX
  21. #define PROG_PREFIX "/"
  22. #endif /* not PROG_PREFIX */
  23.  
  24. /* Message catalogue name. */
  25. #define CAT_NAME "sgmls"
  26. /* Message set to use for application error messages. */
  27. #define APP_SET 4
  28.  
  29. #ifdef HAVE_EXTENDED_PRINTF
  30. #define xvfprintf vfprintf
  31. #else
  32. extern int xvfprintf P((FILE *, char *, va_list));
  33. #endif
  34.  
  35. static VOID usage P((void));
  36. static VOID fatal VP((int, ...));
  37. static VOID do_error P((int, va_list));
  38. static VOID print_caps P((FILE *, struct sgmlcap *));
  39. static VOID swinit P((struct switches *));
  40. static VOID write_caps P((char *, struct sgmlcap *));
  41.  
  42. static UNIV make_docent P((int, char **));
  43. static char *munge_program_name P((char *, char *));
  44. #ifdef SUPPORT_SUBDOC
  45. static VOID build_subargv P((struct switches *));
  46. static VOID cleanup P((void));
  47. static char *create_subcap_file P((void));
  48. #endif
  49.  
  50. static char *errlist[] = {
  51.      0,
  52.      "Out of memory",
  53.      "Cannot open SGML document entity",
  54.      "Cannot exec `%s': %s",
  55.      "Cannot fork: %s",
  56.      "Error waiting for process: %s",
  57.      "Program %s got fatal signal %d",
  58.      "Cannot open `%s': %s",
  59.      "Subdocument capacity botch",
  60. };
  61.  
  62. int suppsw = 0;            /* Non-zero means suppress output. */
  63. int locsw = 0;            /* Non-zero means generate location info. */
  64. static int capsw = 0;        /* Non-zero means print capacity usage. */
  65. static char *prog;        /* Program name (for error messages). */
  66. static nl_catd catd;        /* Message catalogue descriptor. */
  67. static char *capfile = 0;    /* File for capacity report. */
  68. extern char *version_string;
  69.  
  70. #define OPTIONS "acdeglo:prsvx:y:z:"
  71.  
  72. #ifdef SUPPORT_SUBDOC
  73. int suberr = 0;            /* Error in subdocument. */
  74. static char *subargv[sizeof(OPTIONS)];
  75. static int subargc = 0;
  76. static char nopenbuf[sizeof(long)*3 + 1];
  77. static char sgmldecl_file[L_tmpnam];
  78. static char subcap_file[L_tmpnam];
  79. #endif
  80.  
  81. int main(argc, argv)
  82. int argc;
  83. char **argv;
  84. {
  85.      static char stderr_buf[BUFSIZ];
  86.      int opt;
  87.      struct sgmlcap cap;
  88.      struct switches sw;
  89.      setbuf(stderr, stderr_buf);
  90.  
  91. #ifdef SUPPORT_SUBDOC
  92.      subargv[subargc++] = argv[0];
  93. #endif
  94.  
  95.      prog = argv[0] = munge_program_name(argv[0], "sgmls");
  96.  
  97.      catd = catopen(CAT_NAME, 0);
  98.      swinit(&sw);
  99.  
  100.      while ((opt = getopt(argc, argv, OPTIONS)) != EOF) {
  101.       switch (opt) {
  102.       case 'a':          /* Check content model ambiguity. */
  103.            sw.swambig = 1;
  104.            break;
  105.       case 'l':          /* Generate location information. */
  106.            locsw = 1;
  107.            break;
  108.       case 'c':          /* Print capacity usage. */
  109.            capsw = 1;
  110.            break;
  111.       case 's':          /* Suppress output. */
  112.            suppsw = 1;
  113.            break;
  114.       case 'd':           /* Report duplicate entity declarations. */
  115.            sw.swdupent = 1;
  116.            break;
  117.       case 'e':           /* Provide entity stack trace in error msg. */
  118.            sw.swenttr = 1;
  119.            break;
  120.       case 'g':           /* Provide GI stack trace in error messages. */
  121.            sw.sweltr = 1;
  122.            break;
  123.       case 'p':          /* Parse only the prolog. */
  124.            sw.onlypro = 1;
  125.            suppsw = 1;
  126.            break;
  127.       case 'r':           /* Give warning for defaulted references. */
  128.            sw.swrefmsg = 1;
  129.            break;
  130.       case 'x':           /* Trace options for the document body. */
  131.            sw.trace = optarg;
  132.            break;
  133.       case 'y':           /* Trace options for the prolog. */
  134.            sw.ptrace =  optarg;
  135.            break;
  136.       case 'v':           /* Print the version number. */
  137.            fprintf(stderr, "sgmls version %s\n", version_string);
  138.            fflush(stderr);
  139.            break;
  140.       case 'z':
  141.            capfile = optarg;
  142.            break;
  143.       case 'o':
  144.            sw.nopen = atol(optarg);
  145.            if (sw.nopen <= 0)
  146.             usage();
  147.            break;
  148.       case '?':
  149.            usage();
  150.       default:
  151.            abort();
  152.       }
  153.      }
  154.      
  155.      if (optind >= argc)
  156.       usage();
  157.  
  158.      (void)sgmlset(&sw);
  159.  
  160. #ifdef SUPPORT_SUBDOC
  161.      build_subargv(&sw);
  162. #endif
  163.      if (sgmlsdoc(make_docent(argc - optind, argv + optind)))
  164.       fatal(E_DOC);
  165.  
  166.      process_document();
  167.      sgmlend(&cap);
  168.      if (capsw)
  169.       print_caps(stderr, &cap);
  170.      if (capfile)
  171.       write_caps(capfile, &cap);
  172. #ifdef SUPPORT_SUBDOC
  173.      cleanup();
  174.      if (suberr)
  175.       exit(EXIT_FAILURE);
  176. #endif /* SUPPORT_SUBDOC */
  177.      exit(sgmlgcnterr() > 0 ? EXIT_FAILURE : EXIT_SUCCESS);
  178. }
  179.  
  180. static char *munge_program_name(arg, dflt)
  181. char *arg, *dflt;
  182. {
  183.      char *p;
  184. #ifdef PROG_STRIP_EXTENSION
  185.      char *ext;
  186. #endif
  187.      if (!arg || !*arg)
  188.       return dflt;
  189.      p = strchr(arg, '\0');
  190.      for (;;) {
  191.       if (p == arg)
  192.            break;
  193.       --p;
  194.       if (strchr(PROG_PREFIX, *p)) {
  195.            p++;
  196.            break;
  197.       }
  198.      }
  199.      arg = p;
  200. #ifdef PROG_STRIP_EXTENSION
  201.      ext = strrchr(arg, '.');
  202.      if (ext) {
  203.       p = (char *)xmalloc(ext - arg + 1);
  204.       memcpy(p, arg, ext - arg);
  205.       p[ext - arg] = '\0';
  206.       arg = p;
  207.      }
  208. #endif /* PROG_STRIP_EXTENSION */
  209. #ifdef PROG_FOLD
  210. #ifdef PROG_STRIP_EXTENSION
  211.      if (!ext) {
  212. #endif
  213.       p = xmalloc(strlen(arg) + 1);
  214.       strcpy(p, arg);
  215.       arg = p;
  216. #ifdef PROG_STRIP_EXTENSION
  217.      }
  218. #endif
  219.      for (p = arg; *p; p++)
  220.       if ('A' <= *p && *p <= 'Z')
  221.            *p = 'a' + (*p - 'A');
  222. #endif /* PROG_FOLD */
  223.      return arg;
  224. }
  225.  
  226. static UNIV make_docent(argc, argv)
  227. int argc;
  228. char **argv;
  229. {
  230.      UNS len = 1;
  231.      int i;
  232.      UNIV res;
  233.      char *ptr;
  234.  
  235.      for (i = 0; i < argc; i++)
  236.       len += strlen(argv[i]) + 1;
  237.      
  238.      res = xmalloc(len);
  239.      ptr = (char *)res;
  240.      for (i = 0; i < argc; i++) {
  241.       strcpy(ptr, argv[i]);
  242.       ptr = strchr(ptr, '\0') + 1;
  243.      }
  244.      *ptr = '\0';
  245.      return res;
  246. }
  247.  
  248.  
  249. static VOID usage()
  250. {
  251.      /* Don't mention -o and -z, since these are for internal use only. */
  252.      fprintf(stderr,
  253.          "Usage: %s [-acdeglrsv] [-x T] [-y T] filename ...\n",
  254.          prog);
  255.      exit(EXIT_FAILURE);
  256. }
  257.  
  258. static VOID swinit(swp)
  259. struct switches *swp;
  260. {
  261.      swp->swenttr = 0;
  262.      swp->sweltr = 0;
  263.      swp->swbufsz = READCNT+2;
  264.      swp->prog = prog;
  265.      swp->delcdata = DELCDATA;
  266.      swp->delsdata = DELSDATA;
  267.      swp->delnonch = DELNONCH;
  268.      swp->addnonch = ADDNONCH;
  269.      swp->swdupent = 0;
  270.      swp->swrefmsg = 0;
  271.      swp->trace = 0;
  272.      swp->ptrace = 0;
  273.      swp->catd = catd;
  274.      swp->swambig = 0;
  275.      swp->nopen = 0;
  276.      swp->onlypro = 0;
  277. }
  278.  
  279. #ifdef SUPPORT_SUBDOC
  280.  
  281. static VOID build_subargv(swp)
  282. struct switches *swp;
  283. {
  284.      if (swp->swambig)
  285.       subargv[subargc++] = "-a";
  286.      if (suppsw)
  287.       subargv[subargc++] = "-s";
  288.      if (locsw)
  289.       subargv[subargc++] = "-l";
  290.      if (swp->swdupent)
  291.       subargv[subargc++] = "-d";
  292.      if (swp->swenttr)
  293.       subargv[subargc++] = "-e";
  294.      if (swp->sweltr)
  295.       subargv[subargc++] = "-g";
  296.      if (swp->swrefmsg)
  297.       subargv[subargc++] = "-r";
  298.      if (swp->trace) {
  299.       subargv[subargc++] = "-x";
  300.       subargv[subargc++] = swp->trace;
  301.      }
  302.      if (swp->ptrace) {
  303.       subargv[subargc++] = "-y";
  304.       subargv[subargc++] = swp->ptrace;
  305.      }
  306.      subargv[subargc++] = "-o";
  307.      sprintf(nopenbuf, "%ld", swp->nopen + 1);
  308.      subargv[subargc++] = nopenbuf;
  309. }
  310.  
  311.  
  312. static
  313. VOID handler(sig)
  314. int sig;
  315. {
  316.      signal(sig, SIG_DFL);
  317.      cleanup();
  318.      raise(sig);
  319. }
  320.  
  321. static
  322. VOID cleanup()
  323. {
  324.      if (sgmldecl_file[0]) {
  325.       (void)remove(sgmldecl_file);
  326.       sgmldecl_file[0] = '\0';
  327.      }
  328.      if (subcap_file[0]) {
  329.       (void)remove(subcap_file);
  330.       subcap_file[0] = '\0';
  331.      }
  332. }
  333.  
  334. static
  335. char *store_sgmldecl()
  336. {
  337.      if (!sgmldecl_file[0]) {
  338.       FILE *fp;
  339.       if (signal(SIGINT, SIG_IGN) != SIG_IGN)
  340.            signal(SIGINT, handler);
  341.       if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
  342.            signal(SIGTERM, handler);
  343. #ifdef SIGPIPE
  344.       if (signal(SIGPIPE, SIG_IGN) != SIG_IGN)
  345.            signal(SIGPIPE, handler);
  346. #endif
  347. #ifdef SIGHUP
  348.       if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
  349.            signal(SIGHUP, handler);
  350. #endif
  351.       tmpnam(sgmldecl_file);
  352.       errno = 0;
  353.       fp = fopen(sgmldecl_file, "w");
  354.       if (!fp)
  355.            fatal(E_OPEN, sgmldecl_file, strerror(errno));
  356.       sgmlwrsd(fp);
  357.       fclose(fp);
  358.      }
  359.      return sgmldecl_file;
  360. }
  361.  
  362. static
  363. char *create_subcap_file()
  364. {
  365.      if (subcap_file[0] == '\0') {
  366.       FILE *fp;
  367.       tmpnam(subcap_file);
  368.       fp = fopen(subcap_file, "w");
  369.       if (!fp)
  370.            fatal(E_OPEN, subcap_file, strerror(errno));
  371.       fclose(fp);
  372.      }
  373.      return subcap_file;
  374. }
  375.  
  376. char **make_argv(id)
  377. UNIV id;
  378. {
  379.      int nfiles;
  380.      char *p;
  381.      char **argv;
  382.      int i;
  383.  
  384.      for (p = (char *)id, nfiles = 0; *p; p = strchr(p, '\0') + 1)
  385.       nfiles++;
  386.      
  387.      argv = (char **)xmalloc((subargc + (capsw*2) + 1 + nfiles + 1)*sizeof(char *));
  388.      memcpy((UNIV)argv, (UNIV)subargv, subargc*sizeof(char *));
  389.      
  390.      i = subargc;
  391.  
  392.      if (capsw) {
  393.       argv[i++] = "-z";
  394.       argv[i++] = create_subcap_file();
  395.      }
  396.  
  397.      argv[i++] = store_sgmldecl();
  398.  
  399.      for (p = (char *)id; *p; p = strchr(p, '\0') + 1)
  400.       argv[i++] = p;
  401.      argv[i] = 0;
  402.      return argv;
  403. }
  404.  
  405. VOID get_subcaps()
  406. {
  407.      long cap[NCAPACITY];
  408.      FILE *fp;
  409.      int i;
  410.  
  411.      if (!subcap_file[0])
  412.       return;
  413.      errno = 0;
  414.      fp = fopen(subcap_file, "r");
  415.      if (!fp)
  416.       fatal(E_OPEN, subcap_file, strerror(errno));
  417.      cap[0] = 0;
  418.      for (i = 1; i < NCAPACITY; i++)
  419.       if (fscanf(fp, "%ld", cap + i) != 1)
  420.            fatal(E_CAPBOTCH);
  421.      fclose(fp);
  422.      sgmlsubcap(cap);
  423. }
  424.  
  425.  
  426. #endif /* SUPPORT_SUBDOC */
  427.  
  428. /* Print capacity statistics.*/
  429.  
  430. static VOID print_caps(fp, p)
  431. FILE *fp;
  432. struct sgmlcap *p;
  433. {
  434.      int i;
  435.      for (i = 0; i < NCAPACITY; i++)
  436.       if (p->number[i])
  437.            fprintf(fp, "%8s %5ld/%ld\n", p->name[i],
  438.                p->number[i]*p->points[i], p->limit[i]);
  439. }
  440.  
  441. static VOID write_caps(name, p)
  442. char *name;
  443. struct sgmlcap *p;
  444. {
  445.      FILE *fp;
  446.      int i;
  447.      fp = fopen(name, "w");
  448.      if (!fp)
  449.       fatal(E_OPEN, name, strerror(errno));
  450.      /* Don't write TOTALCAP. */
  451.      for (i = 1; i < NCAPACITY; i++)
  452.       fprintf(fp, "%ld\n", p->number[i]);
  453.      fclose(fp);
  454. }
  455.  
  456. UNIV xmalloc(n)
  457. UNS n;
  458. {
  459.      UNIV p = malloc(n);
  460.      if (!p)
  461.       fatal(E_NOMEM);
  462.      return p;
  463. }
  464.  
  465. static
  466. #ifdef VARARGS
  467. VOID fatal(va_alist) va_dcl
  468. #else
  469. VOID fatal(int errnum,...)
  470. #endif
  471. {
  472. #ifdef VARARGS
  473.      int errnum;
  474. #endif
  475.      va_list ap;
  476.      
  477. #ifdef VARARGS
  478.      va_start(ap);
  479.      errnum = va_arg(ap, int);
  480. #else
  481.      va_start(ap, errnum);
  482. #endif
  483.      do_error(errnum, ap);
  484.      va_end(ap);
  485.      exit(EXIT_FAILURE);
  486. }
  487.  
  488. #ifdef VARARGS
  489. VOID appl_error(va_alist) va_dcl
  490. #else
  491. VOID appl_error(int errnum,...)
  492. #endif
  493. {
  494. #ifdef VARARGS
  495.      int errnum;
  496. #endif
  497.      va_list ap;
  498.      
  499. #ifdef VARARGS
  500.      va_start(ap);
  501.      errnum = va_arg(ap, int);
  502. #else
  503.      va_start(ap, errnum);
  504. #endif
  505.      do_error(errnum, ap);
  506.      va_end(ap);
  507. }
  508.  
  509. static
  510. VOID do_error(errnum, ap)
  511. int errnum;
  512. va_list ap;
  513. {
  514.      char *text;
  515.      fprintf(stderr, "%s: ", prog);
  516.      assert(errnum > 0);
  517.      assert(errnum < sizeof(errlist)/sizeof(errlist[0]));
  518.      text = catgets(catd, APP_SET, errnum, errlist[errnum]);
  519.      assert(text != 0);
  520.      xvfprintf(stderr, text, ap);
  521.      fputc('\n', stderr);
  522.      fflush(stderr);
  523. }
  524.  
  525. /*
  526. Local Variables:
  527. c-indent-level: 5
  528. c-continued-statement-offset: 5
  529. c-brace-offset: -5
  530. c-argdecl-indent: 0
  531. c-label-offset: -5
  532. comment-column: 30
  533. End:
  534. */
  535.